/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/********************************************************************************************************
 * \file     Mcal_MemLibc.c                                                                             *
 * \brief    AUTOSAR 4.3.1 MCAL DMA Driver                                                              *
 *                                                                                                      *
 * <table>                                                                                              *
 * <tr><th>Date           <th>Version                                                                   *
 * <tr><td>2025/01/06     <td>1.0.0                                                                     *
 * </table>                                                                                             *
 *******************************************************************************************************/
#ifdef __cplusplus
extern *C* {
#endif

#if defined(_IAR_C_)
#pragma optimize=none
#elif defined(_GCC_C_)
#pragma GCC optimize ("O0")
#endif
/********************************************************************************************************
 *                                      Include header files                                            *
 *******************************************************************************************************/
#include "Mcal_Types.h"
#include "Mcal_MemLibc.h"
/********************************************************************************************************
 *                                 Private Macro definition                                             *
 *******************************************************************************************************/
/** \brief  the max physical address value. */
#define MEM_MAX_RANGE                                                       (0xFFFFFFFFU)
/********************************************************************************************************
 *                                  Private Function Declarations                                       *
 *******************************************************************************************************/
extern void *memcpy_4bytes_aligned(void *dst, const void *src, uint32 bytes);
extern void *memclr_4bytes_aligned(void *dst, uint32 bytes);

#define MCALLIB_START_SEC_CODE
#include "McalLib_MemMap.h"
/********************************************************************************************************
 *                                  Global Function Declarations                                        *
 *******************************************************************************************************/
/** *****************************************************************************************************
 * \brief This function copy the data from source to destnation.
 *
 * \verbatim
 * Syntax             : Std_ReturnType Mcal_MemCpy
 *                      (
 *                          void *dst
 *                          const void *src
 *                          uint32 size
 *                      )
 *
 * Service ID[hex]    : 0x00
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Reentrant
 *
 * Parameters (in)    : dst - pointer to destination address
 *                      src - pointer to source address
 *                      size - copy size
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : E_OK: Copy success.
 *                      MCALLIB_E_PARAM_POINTER: Input address is null.
 *                      MCALLIB_E_PARAM_SIZE: Input size is error.
 *
 * Description        : serves as an alternative to the C standard library
 *                      for implementing memory copy functionality.
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
Std_ReturnType Mcal_MemCpy(void *dst, const void *src, uint32 size)
{
    /* ----- Local Variables ---------------------------------------------- */
    Std_ReturnType errorId = E_OK;
    /*PRQA S 0326, 0316 6*/
    uint32 alignSrc = (uint32)src % 4UL;
    uint32 alignDst = (uint32)dst % 4UL;
    uint8 *dstPtr = (uint8 *)dst;
    const uint8 *srcPtr = (const uint8 *)src;
    uint32 index;
    uint32 bytes;
    uint32 memSize = size;

    /* #10 copy from 0 is allowed */
    if (NULL_PTR == dstPtr)
    {
        errorId = MCALLIB_E_PARAM_POINTER;
    }
    /*PRQA S 0306 2*/
    else if (((MEM_MAX_RANGE - (uint32)dstPtr) < (uint32)size) ||
            ((MEM_MAX_RANGE- (uint32)srcPtr) < (uint32)size) || (0UL == size))
    {
        errorId = MCALLIB_E_PARAM_SIZE;
    }
    else
    {
        if (alignSrc != alignDst)
        {
            for (; memSize > 0UL; memSize--)
            {
                *dstPtr = *srcPtr;
                dstPtr++;
                srcPtr++;
            }
        }
        else
        {
            if (0UL != alignSrc)
            {
                bytes = (memSize > (4UL - alignDst)) ? (4UL - alignDst) : memSize;

                for (index = 0UL; index < bytes ; index++)
                {
                    *dstPtr = *srcPtr;
                    memSize--;
                    dstPtr++;
                    srcPtr++;
                }
            }

            if (memSize > 4UL)
            {
                bytes = memSize / 4UL * 4UL;
#if defined(CFG_MEMCPY_ASM_OPTIMIZED)
                /*PRQA S 3200, 0315 2*/
                (void *)memcpy_4bytes_aligned(dstPtr, srcPtr, bytes);
                /*PRQA S 0488 10*/
                dstPtr += bytes;
                srcPtr += bytes;
#else
                uint32 *u32SrcPtr = (uint32 *)srcPtr;
                uint32 *u32DstPtr = (uint32 *)dstPtr;
                for (index = 0UL; index < bytes / 4UL; index++)
                {
                    *u32DstPtr++ = *u32SrcPtr++;
                    srcPtr += 4UL;
                    dstPtr += 4UL;
                }
#endif
                memSize -= bytes;
            }

            for (; memSize > 0UL; memSize--)
            {
                *dstPtr = *srcPtr;
                dstPtr++;
                srcPtr++;
            }
        }
    }

    return errorId;
}
/** *****************************************************************************************************
 * \brief This function implement memory clear.
 *
 * \verbatim
 * Syntax             : Std_ReturnType Mcal_MemClr
 *                      (
 *                          void *dst
 *                          uint32 size
 *                      )
 *
 * Service ID[hex]    : 0x01
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Reentrant
 *
 * Parameters (in)    : dst - pointer to destination address
 *                      size - copy size
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : E_OK: Clear success.
 *                      MCALLIB_E_PARAM_POINTER: Input address is null.
 *                      MCALLIB_E_PARAM_SIZE: Input size is error.
 *
 * Description        : serves as an alternative to the C standard library
 *                      for implementing memory clear functionality.
 *
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
Std_ReturnType Mcal_MemClr(void *dst, uint32 size)
{
    /* ----- Local Variables ---------------------------------------------- */
    Std_ReturnType errorId = E_OK;
    /*PRQA S 0326, 0316 3*/
    uint32 align = (uint32)dst % 4U;
    uint32 bytes;
    uint8 *dstPtr = (uint8 *)dst;
    uint32 memSize = size;

    if (NULL_PTR == dstPtr)
    {
        errorId = MCALLIB_E_PARAM_POINTER;
    }
    /*PRQA S 0306 1*/
    else if (((MEM_MAX_RANGE - (uint32)dstPtr) < size) || (0UL == size))
    {
        errorId = MCALLIB_E_PARAM_SIZE;
    }
    else
    {
        if (align != 0U)
        {
            bytes = (memSize > (4U - align)) ? (4U - align) : memSize;

            for (; bytes > 0U; bytes--)
            {
                *dstPtr = 0U;
                memSize--;
                dstPtr++;
            }
        }

        if (memSize > 4U)
        {
            bytes = memSize / 4U * 4U;
#if defined(CFG_MEMCLR_ASM_OPTIMIZED)
            /*PRQA S 3200, 0315 2*/
            (void *)memclr_4bytes_aligned(dstPtr, bytes);
            memSize -= bytes;
            /*PRQA S 0488 1*/
            dstPtr += bytes;
#else
            uint32 *u32DstPtr = (uint32 *)dstPtr;
            for (; bytes > 0U; bytes -= 4U)
            {
                *u32DstPtr = 0UL;
                 memSize -= 4U;
                 dstPtr += 4U;
                 u32DstPtr++;
            }

#endif /* #if defined(CFG_MEMCLR_ASM_OPTIMIZED) */
        }

        for (; memSize > 0U; memSize--)
        {
            *dstPtr = 0U;
            dstPtr++;
        }
    }

    return errorId;
}
/** *****************************************************************************************************
 * \brief This function implement memory compare.
 *
 * \verbatim
 * Syntax             : Std_ReturnType Mcal_MemCmp
 *                      (
 *                          const void *mem1
 *                          const void *mem2
 *                          uint32 size
 *                      )
 *
 * Service ID[hex]    : 0x02
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Reentrant
 *
 * Parameters (in)    : mem1 - pointer to a memory block
 *                      mem2 - pointer to a memory block
 *                      size - compare size
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : E_OK: mem1 == mem2.
 *                      MCALLIB_E_PARAM_POINTER: Input address is null.
 *                      MCALLIB_E_PARAM_SIZE: Input size is error.
 *                      MCALLIB_E_MEM_CMP_FAIL: mem1 != mem2.
 *
 * Description        : memcmp is not heavily used in this project, so the char by char comparision is
 *                      acceptable here.
 *
 * \endverbatim
 * Traceability       : SWSR SWSR_LIB_015
 *******************************************************************************************************/
Std_ReturnType Mcal_MemCmp(const void *mem1, const void *mem2, uint32 size)
{
    /* ----- Local Variables ---------------------------------------------- */
    Std_ReturnType errorId = E_OK;
    /*PRQA S 0316 1*/
    const uint8 *mem1Ptr = (const uint8 *)mem1, *mem2Ptr = (const uint8 *)mem2;
    uint32 memSize = size;

    if ((NULL_PTR == mem1) || (NULL_PTR == mem2))
    {
        errorId = MCALLIB_E_PARAM_POINTER;
    }
    /*PRQA S 0326 2*/
    else if (((MEM_MAX_RANGE - (uint32)mem1) < (uint32)size) ||
            ((MEM_MAX_RANGE- (uint32)mem2) < (uint32)size) || (0UL == size))
    {
        errorId = MCALLIB_E_PARAM_SIZE;
    }
    else
    {
        for (; memSize > 0UL; memSize--)
        {
            if (*mem1Ptr != *mem2Ptr)
            {
                errorId = MCALLIB_E_MEM_CMP_FAIL;
                break;
            }
            mem1Ptr++;
            mem2Ptr++;
        }
    }

    return errorId;
}
/** *****************************************************************************************************
 * \brief This function implement memory set.
 *
 * \verbatim
 * Syntax             : Std_ReturnType Mcal_MemSet
 *                      (
 *                          void *dst
 *                          int val
 *                          uint32 size
 *                      )
 *
 * Service ID[hex]    : 0x03
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Reentrant
 *
 * Parameters (in)    : dst - point to destination of memset
 *                      val - default value to be set
 *                      size - size to be write, unit is in bytes.
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : return the length of the address after the data has been written.
 *
 * Description        : The function is used to set a specific value to a given length of a memory block.
 *
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
Std_ReturnType Mcal_MemSet(void *dst, uint32 val, uint32 size)
{
    /* ----- Local Variables ---------------------------------------------- */
    Std_ReturnType errorId = E_OK;
    /*PRQA S 0316 1*/
    uint8 *dstPtr = (uint8 *)dst;
    uint32 memSize = size;

    if (NULL_PTR == dstPtr)
    {
        errorId = MCALLIB_E_PARAM_POINTER;
    }
    /*PRQA S 0306 1*/
    else if (((MEM_MAX_RANGE - (uint32)dstPtr) < (uint32)size) || (0UL == size))
    {
        errorId = MCALLIB_E_PARAM_SIZE;
    }
    else
    {
        for (; memSize > 0U; memSize--)
        {
            *dstPtr = (uint8)val;
            dstPtr++;
        }
    }

    return errorId;
}
/** *****************************************************************************************************
 * \brief This function implement data reversal.
 *
 * \verbatim
 * Syntax             : Std_ReturnType Mcal_MemRvs
 *                      (
 *                          void *mem
 *                          uint32 size
 *                      )
 *
 * Service ID[hex]    : 0x04
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Reentrant
 *
 * Parameters (in)    : dst - pointer to data need be reverse.
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : Implementing data reversal functionality one by one.
 *
 * \endverbatim
 * Traceability       :
 *******************************************************************************************************/
Std_ReturnType Mcal_MemRvs(void *mem, uint32 size)
{
    /* ----- Local Variables ---------------------------------------------- */
    Std_ReturnType errorId = E_OK;
    uint32 n = (size + 1UL) / 2UL;
    /*PRQA S 0316, 0306, 0326 2*/
    uint8 *begin = (uint8 *)mem;
    uint8 *end = (uint8 *)((uint32)(mem) + size - 1UL);
    uint8 tmp;

    if (NULL_PTR == mem)
    {
        errorId = MCALLIB_E_PARAM_POINTER;
    }
    /*PRQA S 0326 1*/
    else if (((MEM_MAX_RANGE - (uint32)mem) < size) || (0UL == size))
    {
        errorId = MCALLIB_E_PARAM_SIZE;
    }
    else
    {
        while (n > 0U)
        {
            tmp = *begin;
            *begin = *end;
            *end = tmp;
            begin++;
            end--;
            n--;
        }
    }

    return errorId;
}

#define MCALLIB_STOP_SEC_CODE
#include "McalLib_MemMap.h"
#ifdef __cplusplus
}
#endif
/* End of file */
